package edu.ucsd.cse222b.network;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class NetFlow {
	
	private static long globalCount=0;
	private long id;
	private EndHost src;
	private EndHost dst;
	private double size;
	private double startTime;
	private double endTime;
	private double remainingSize;
	private double requiredBandwidth;
	private double currentBandwidth;
	private double availableBandwidth;
	private List<Link> links=new ArrayList<Link>();
	private boolean saturated;
	
	public NetFlow(EndHost src, EndHost dst, double size, double startTime, double endTime){
		this.src=src;
		this.dst=dst;
		this.size=size;
		this.startTime=startTime;
		this.endTime=endTime;
		this.remainingSize=size;
		this.requiredBandwidth=size/(endTime-startTime);
		this.availableBandwidth=0;
		this.currentBandwidth=0;
		this.saturated=false;
		id=globalCount++;
	}
	
	public long getId(){
		return id;
	}
	
	public void setSource(EndHost src){
		this.src=src;
	}
	
	public EndHost getSource(){
		return src;
	}
	
	public void setDestination(EndHost dst){
		this.dst=dst;
	}
	
	public EndHost getDestination(){
		return dst;
	}
	
	public double getSize(){
		return size;
	}
	
	public double getStartTime(){
		return startTime;
	}
	
	public double getEndTime(){
		return endTime;
	}
	
	public double getRemainingSize(){
		return remainingSize;
	}
	
	public double getRequiredBandwidth(){
		return requiredBandwidth;
	}
	
	public double getCurrentBandwidth(){
		return currentBandwidth;
	}
	
	public void setCurrentBandwidth(double curBw){
		currentBandwidth=curBw;
	}
	
	public void acceptBandwidth(){
		currentBandwidth=(availableBandwidth>=requiredBandwidth)? requiredBandwidth : availableBandwidth;
	}
	
	public void increaseAvailableBandwidth(double d){
		availableBandwidth+=d;
	}
	
	public void decreaseAvailableBandwidth(double d){
		availableBandwidth-=d;
	}
	
	public void setAvailableBandwidth(double d){
		availableBandwidth=d;
	}
	
	public void doTransfer(double transferTime){
		//bw allo already finished
		remainingSize-=transferTime*currentBandwidth;
		if(transferTime>0){
			System.out.println("flow "+id+" transferred "+transferTime*currentBandwidth+" bytes in "+transferTime+" sec, rate="+currentBandwidth);
			if(remainingSize<=0){
				System.out.println("flow "+id+" finished");
			}
		}
	}
	
	public Set<NetNode> getRouters()
	{
		Set<NetNode> routers = new HashSet<NetNode>();
		for(Link link : links){
			if(link.getDstNode()!=dst)
			{
				routers.add(link.getDstNode());
			}
		}
		return routers;
		
	}
	
	public void setLinks(List<Link> links){
		this.links = links;
	}
	
	public List<Link> getLinks(){
		return links;
	}

	public boolean isSaturated() {
		return saturated;
	}

	public void setSaturated(boolean saturated) {
		this.saturated = saturated;
	}
	
	public String toString(){
		String result="flow id: "+ id+" quota="+availableBandwidth+ " usage="+currentBandwidth+" "+src+"->";
		for(Link link : links){
			if(link.getDstNode()!=dst){
				result+=link.getDstNode()+"->";
			}else{
				result+=link.getDstNode();
			}
		}
		return result;
	}
}
